home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / gdevcgml.c < prev    next >
C/C++ Source or Header  |  1996-09-02  |  27KB  |  991 lines

  1. /* Copyright (C) 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevcgml.c */
  20. /* CGM-writing library */
  21. #include "memory_.h"
  22. #include "stdio_.h"
  23. #include "gdevcgmx.h"
  24.  
  25. /* Forward references to command-writing procedures */
  26. private void begin_command(P2(cgm_state *, cgm_op_index));
  27. #define OP(op) begin_command(st, op)
  28. private cgm_result end_command(P1(cgm_state *));
  29. #define END_OP (void)end_command(st)
  30. #define END return end_command(st)
  31. /* Parameters */
  32. private void put_int(P3(cgm_state *, cgm_int, int));
  33. #define CI(ci) put_int(st, ci, st->metafile.color_index_precision)
  34. #define I(i) put_int(st, i, st->metafile.integer_precision)
  35. #define IX(ix) put_int(st, ix, st->metafile.index_precision)
  36. #define E(e) put_int(st, (int)(e), 16)
  37. private void put_real(P3(cgm_state *, cgm_real, const cgm_precision *));
  38. #define R(r) put_real(st, r, &st->metafile.real_precision)
  39. private void put_vdc(P2(cgm_state *, const cgm_vdc *));
  40. #define VDC(vdc) put_vdc(st, vdc)
  41. #define VDC2(vdc1, vdc2) VDC(vdc1); VDC(vdc2)
  42. #define VDC4(vdc1, vdc2, vdc3, vdc4) VDC2(vdc1, vdc2); VDC2(vdc3, vdc4)
  43. private void put_vdc_r(P3(cgm_state *, const cgm_line_marker_extent *, cgm_line_marker_specification_mode));
  44. #define VDC_R(vdcr, mode) put_vdc_r(st, vdcr, mode)
  45. private void put_point(P2(cgm_state *, const cgm_point *));
  46. #define P(p) put_point(st, p)
  47. private void put_points(P3(cgm_state *, const cgm_point *, int));
  48. #define nP(p, n) put_points(st, p, n)
  49. private void put_string(P3(cgm_state *, const char *, uint));
  50. #define S(s, l) put_string(st, s, l)
  51. private void put_color(P2(cgm_state *, const cgm_color *));
  52. #define CO(co) put_color(st, co)
  53. private void put_rgb(P2(cgm_state *, const cgm_rgb *));
  54. #define CD(cd) put_rgb(st, cd)
  55. /* Other data types */
  56. #define put_byte(st, b)\
  57.   if ( st->command_count == command_max_count ) write_command(st, false);\
  58.   st->command[st->command_count++] = (byte)(b)
  59. private void put_bytes(P3(cgm_state *, const byte *, uint));
  60. private void write_command(P2(cgm_state *, bool));
  61. private void put_real_precision(P2(cgm_state *, const cgm_precision *));
  62.  
  63. /* ================ Public routines ================ */
  64.  
  65. /* ---------------- Initialize/terminate ---------------- */
  66.  
  67. /* Initialize a CGM writer. */
  68. cgm_state *
  69. cgm_initialize(FILE *file, const cgm_allocator *cal)
  70. {    cgm_state *st = (*cal->alloc)(cal->private_data, sizeof(cgm_state));
  71.     if ( st == 0 )
  72.       return 0;
  73.     st->file = file;
  74.     st->allocator = *cal;
  75.         /* Initialize metafile elements. */
  76.     st->metafile.vdc_type = cgm_vdc_integer;
  77.     st->metafile.integer_precision = 16;
  78.     st->metafile.real_precision.representation = cgm_representation_fixed;
  79.     st->metafile.real_precision.exponent_or_whole_width = 16;
  80.     st->metafile.real_precision.fraction_width = 16;
  81.     st->metafile.index_precision = 16;
  82.     st->metafile.color_precision = 8;
  83.     st->metafile.color_index_precision = 8;
  84.     st->metafile.maximum_color_index = 63;
  85.     /* color_value_extent */
  86.     /*st->metafile.character_coding_announcer = 0;*/
  87.         /* Initialize picture elements. */
  88.     st->picture.scaling_mode = cgm_scaling_abstract;
  89.     st->picture.color_selection_mode = cgm_color_selection_indexed;
  90.     st->picture.line_width_specification_mode = cgm_line_marker_absolute;
  91.     st->picture.marker_size_specification_mode = cgm_line_marker_absolute;
  92.     st->picture.edge_width_specification_mode = cgm_line_marker_absolute;
  93.     /* vdc_extent */
  94.     /* background_color */
  95.         /* Initialize control elements. */
  96.     st->vdc_integer_precision = st->metafile.integer_precision;
  97.     st->vdc_real_precision = st->metafile.real_precision;
  98.     st->transparency = cgm_transparency_on;
  99.     /* clip_rectangle */
  100.     st->clip_indicator = cgm_clip_on;
  101.         /* Initialize other state elements. */
  102.     st->line_bundle_index = 1;
  103.     st->line_type = cgm_line_solid;
  104.     /* line_width */
  105.     /* line_color */
  106.     st->marker_bundle_index = 1;
  107.     st->marker_type = cgm_marker_asterisk;
  108.     /* marker_size */
  109.     /* marker_color */
  110.     st->text_bundle_index = 1;
  111.     st->text_font_index = 1;
  112.     st->text_precision = cgm_text_precision_string;
  113.     st->character_expansion_factor = 1.0;
  114.     st->character_spacing = 0.0;
  115.     /* text_color */
  116.     /* character_height */
  117.     /* character_orientation */
  118.     st->text_path = cgm_text_path_right;
  119.     /* text_alignment */
  120.     st->character_set_index = 1;
  121.     st->alternate_character_set_index = 1;
  122.     st->fill_bundle_index = 1;
  123.     st->interior_style = cgm_interior_style_hollow;
  124.     st->hatch_index = cgm_hatch_horizontal;
  125.     st->pattern_index = 1;
  126.     st->edge_bundle_index = 1;
  127.     st->edge_type = cgm_edge_solid;
  128.     /* edge_width */
  129.     st->edge_visibility = false;
  130.     /* fill_reference_point */
  131.     /* pattern_table */
  132.     /* pattern_size */
  133.     /* color_table */
  134.     memset(st->source_flags, (byte)cgm_aspect_source_individual,
  135.            sizeof(st->source_flags));
  136.     return st;
  137. }
  138.  
  139. /* Terminate a CGM writer. */
  140. cgm_result
  141. cgm_terminate(cgm_state *st)
  142. {    (*st->allocator.free)(st->allocator.private_data, st);
  143.     return cgm_result_ok;
  144. }
  145.  
  146. /* ---------------- Metafile elements ---------------- */
  147.  
  148. cgm_result
  149. cgm_BEGIN_METAFILE(cgm_state *st, const char *str, uint len)
  150. {    OP(BEGIN_METAFILE);
  151.     S(str, len);
  152.     END;
  153. }
  154.  
  155. cgm_result
  156. cgm_set_metafile_elements(cgm_state *st, const cgm_metafile_elements *meta, long mask)
  157. {    if ( (mask & cgm_set_METAFILE_VERSION) )
  158.       {    OP(METAFILE_VERSION);
  159.         I(meta->metafile_version);
  160.         END_OP;
  161.         st->metafile.metafile_version = meta->metafile_version;
  162.       }
  163.     if ( (mask & cgm_set_METAFILE_DESCRIPTION) )
  164.       {    OP(METAFILE_DESCRIPTION);
  165.         S(meta->metafile_description.chars, meta->metafile_description.length);
  166.         END_OP;
  167.         st->metafile.metafile_description = meta->metafile_description;
  168.       }
  169.     if ( (mask & cgm_set_VDC_TYPE) )
  170.       {    OP(VDC_TYPE);
  171.         E(meta->vdc_type);
  172.         END_OP;
  173.         st->metafile.vdc_type = meta->vdc_type;
  174.       }
  175.     if ( (mask & cgm_set_INTEGER_PRECISION) )
  176.       {    OP(INTEGER_PRECISION);
  177.         I(meta->integer_precision);
  178.         END_OP;
  179.         st->metafile.integer_precision = meta->integer_precision;
  180.       }
  181.     if ( (mask & cgm_set_REAL_PRECISION) )
  182.       {    OP(REAL_PRECISION);
  183.         put_real_precision(st, &meta->real_precision);
  184.         END_OP;
  185.         st->metafile.real_precision = meta->real_precision;
  186.       }
  187.     if ( (mask & cgm_set_INDEX_PRECISION) )
  188.       {    OP(INDEX_PRECISION);
  189.         I(meta->index_precision);
  190.         END_OP;
  191.         st->metafile.index_precision = meta->index_precision;
  192.       }
  193.     if ( (mask & cgm_set_COLOR_PRECISION) )
  194.       {    OP(COLOR_PRECISION);
  195.         I(meta->color_precision);
  196.         END_OP;
  197.         st->metafile.color_index_precision = meta->color_index_precision;
  198.       }
  199.     if ( (mask & cgm_set_COLOR_INDEX_PRECISION) )
  200.       {    OP(COLOR_INDEX_PRECISION);
  201.         I(meta->color_index_precision);
  202.         END_OP;
  203.         st->metafile.color_index_precision = meta->color_index_precision;
  204.       }
  205.     if ( (mask & cgm_set_MAXIMUM_COLOR_INDEX) )
  206.       {    OP(MAXIMUM_COLOR_INDEX);
  207.         CI(meta->maximum_color_index);
  208.         END_OP;
  209.         st->metafile.maximum_color_index = meta->maximum_color_index;
  210.       }
  211.     if ( (mask & cgm_set_METAFILE_ELEMENT_LIST) )
  212.       {    int i;
  213.         const int *p;
  214.         OP(METAFILE_ELEMENT_LIST);
  215.         for ( i = 0, p = meta->metafile_element_list;
  216.               i < meta->metafile_element_list_count;
  217.               i++, p += 2
  218.             )
  219.           {    I(p[0]); I(p[1]);
  220.           }
  221.         END_OP;
  222.         st->metafile.metafile_element_list =
  223.           meta->metafile_element_list;
  224.         st->metafile.metafile_element_list_count =
  225.           meta->metafile_element_list_count;
  226.       }
  227.     /* element list */
  228.     if ( (mask & cgm_set_FONT_LIST) )
  229.       {    int i;
  230.         OP(FONT_LIST);
  231.         for ( i = 0; i < meta->font_list_count; ++i )
  232.           S(meta->font_list[i].chars, meta->font_list[i].length);
  233.         END_OP;
  234.         st->metafile.font_list = meta->font_list;
  235.         st->metafile.font_list_count = meta->font_list_count;
  236.       }
  237.     /* character set list */
  238.     /* character coding announcer */
  239.     return st->result;
  240. }
  241.  
  242. cgm_result
  243. cgm_END_METAFILE(cgm_state *st)
  244. {    OP(END_METAFILE);
  245.     END;
  246. }
  247.  
  248. /* ---------------- Picture elements ---------------- */
  249.  
  250. cgm_result
  251. cgm_BEGIN_PICTURE(cgm_state *st, const char *str, uint len)
  252. {    OP(BEGIN_PICTURE);
  253.     S(str, len);
  254.     END;
  255. }
  256.  
  257. cgm_result
  258. cgm_set_picture_elements(cgm_state *st, const cgm_picture_elements *pic, long mask)
  259. {    if ( (mask & cgm_set_SCALING_MODE) )
  260.       {    OP(SCALING_MODE);
  261.         E(pic->scaling_mode);
  262.         R(pic->scale_factor);
  263.         st->picture.scaling_mode = pic->scaling_mode;
  264.         st->picture.scale_factor = pic->scale_factor;
  265.         END_OP;
  266.       }
  267.     if ( (mask & cgm_set_COLOR_SELECTION_MODE) )
  268.       {    OP(COLOR_SELECTION_MODE);
  269.         E(pic->color_selection_mode);
  270.         END_OP;
  271.         st->picture.color_selection_mode = pic->color_selection_mode;
  272.       }
  273.     if ( (mask & cgm_set_LINE_WIDTH_SPECIFICATION_MODE) )
  274.       {    OP(LINE_WIDTH_SPECIFICATION_MODE);
  275.         E(pic->line_width_specification_mode);
  276.         END_OP;
  277.         st->picture.line_width_specification_mode = pic->line_width_specification_mode;
  278.       }
  279.     if ( (mask & cgm_set_MARKER_SIZE_SPECIFICATION_MODE) )
  280.       {    OP(MARKER_SIZE_SPECIFICATION_MODE);
  281.         E(pic->marker_size_specification_mode);
  282.         END_OP;
  283.         st->picture.marker_size_specification_mode = pic->marker_size_specification_mode;
  284.       }
  285.     if ( (mask & cgm_set_EDGE_WIDTH_SPECIFICATION_MODE) )
  286.       {    OP(EDGE_WIDTH_SPECIFICATION_MODE);
  287.         E(pic->edge_width_specification_mode);
  288.         END_OP;
  289.         st->picture.edge_width_specification_mode = pic->edge_width_specification_mode;
  290.       }
  291.     if ( (mask & cgm_set_VDC_EXTENT) )
  292.       {    OP(VDC_EXTENT);
  293.         P(&pic->vdc_extent[0]);
  294.         P(&pic->vdc_extent[1]);
  295.         END_OP;
  296.         st->picture.vdc_extent[0] = pic->vdc_extent[0];
  297.         st->picture.vdc_extent[1] = pic->vdc_extent[1];
  298.       }
  299.     if ( (mask & cgm_set_BACKGROUND_COLOR) )
  300.       {    OP(BACKGROUND_COLOR);
  301.         CD(&pic->background_color.rgb);
  302.         END;
  303.         st->picture.background_color = pic->background_color;
  304.       }
  305.     return st->result;
  306. }
  307.  
  308. cgm_result
  309. cgm_BEGIN_PICTURE_BODY(cgm_state *st)
  310. {    OP(BEGIN_PICTURE_BODY);
  311.     END;
  312. }
  313.  
  314. cgm_result
  315. cgm_END_PICTURE(cgm_state *st)
  316. {    OP(END_PICTURE);
  317.     END;
  318. }
  319.  
  320. /* ---------------- Control elements ---------------- */
  321.  
  322. cgm_result
  323. cgm_VDC_INTEGER_PRECISION(cgm_state *st, int precision)
  324. {    if ( st->vdc_integer_precision != precision )
  325.       {    OP(VDC_INTEGER_PRECISION);
  326.         I(precision);  st->vdc_integer_precision = precision;
  327.         END;
  328.       }
  329.     else
  330.       return cgm_result_ok;
  331. }
  332.  
  333. cgm_result
  334. cgm_VDC_REAL_PRECISION(cgm_state *st, const cgm_precision *precision)
  335. {    OP(VDC_REAL_PRECISION);
  336.     put_real_precision(st, precision);  st->vdc_real_precision = *precision;
  337.     END;
  338. }
  339.  
  340. cgm_result
  341. cgm_AUXILIARY_COLOR(cgm_state *st, const cgm_color *color)
  342. {    OP(AUXILIARY_COLOR);
  343.     CO(color);  st->auxiliary_color = *color;
  344.     END;
  345. }
  346.  
  347. cgm_result
  348. cgm_TRANSPARENCY(cgm_state *st, cgm_transparency transparency)
  349. {    OP(TRANSPARENCY);
  350.     E(transparency);  st->transparency = transparency;
  351.     END;
  352. }
  353.  
  354. cgm_result
  355. cgm_CLIP_RECTANGLE(cgm_state *st, const cgm_point rectangle[2])
  356. {    OP(CLIP_RECTANGLE);
  357.     P(&rectangle[0]);  st->clip_rectangle[0] = rectangle[0];
  358.     P(&rectangle[1]);  st->clip_rectangle[1] = rectangle[1];
  359.     END;
  360. }
  361.  
  362. cgm_result
  363. cgm_CLIP_INDICATOR(cgm_state *st, cgm_clip_indicator clip)
  364. {    OP(CLIP_INDICATOR);
  365.     E(clip);  st->clip_indicator = clip;
  366.     END;
  367. }
  368.  
  369. /* ---------------- Graphical primitive elements ---------------- */
  370.  
  371. cgm_result
  372. cgm_POLYLINE(cgm_state *st, const cgm_point *vertices, int count)
  373. {    OP(POLYLINE);
  374.     nP(vertices, count);
  375.     END;
  376. }
  377.  
  378. cgm_result
  379. cgm_DISJOINT_POLYLINE(cgm_state *st, const cgm_point *endpoints, int count)
  380. {    OP(DISJOINT_POLYLINE);
  381.     nP(endpoints, count);
  382.     END;
  383. }
  384.  
  385. cgm_result
  386. cgm_POLYMARKER(cgm_state *st, const cgm_point *positions, int count)
  387. {    OP(POLYMARKER);
  388.     nP(positions, count);
  389.     END;
  390. }
  391.  
  392. cgm_result
  393. cgm_TEXT(cgm_state *st, const cgm_point *position, bool final, const char *str, uint len)
  394. {    OP(TEXT);
  395.     P(position); E(final); S(str, len);
  396.     END;
  397. }
  398.  
  399. cgm_result
  400. cgm_RESTRICTED_TEXT(cgm_state *st, const cgm_vdc *delta_width, const cgm_vdc *delta_height, const cgm_point *position, bool final, const char *str, uint len)
  401. {    OP(RESTRICTED_TEXT);
  402.     VDC2(delta_width, delta_height); P(position); E(final); S(str, len);
  403.     END;
  404. }
  405.  
  406. cgm_result
  407. cgm_APPEND_TEXT(cgm_state *st, bool final, const char *str, uint len)
  408. {    OP(APPEND_TEXT);
  409.     E(final); S(str, len);
  410.     END;
  411. }
  412.  
  413. cgm_result
  414. cgm_POLYGON(cgm_state *st, const cgm_point *vertices, int count)
  415. {    OP(POLYGON);
  416.     nP(vertices, count);
  417.     END;
  418. }
  419.  
  420. cgm_result
  421. cgm_POLYGON_SET(cgm_state *st, const cgm_polygon_edge *vertices, int count)
  422. {    int i;
  423.     OP(POLYGON);
  424.     for ( i = 0; i < count; ++i )
  425.     {    P(&vertices[i].vertex);
  426.         E(vertices[i].edge_out);
  427.     }
  428.     END;
  429. }
  430.  
  431. cgm_result
  432. cgm_CELL_ARRAY(cgm_state *st, const cgm_point *pqr /*[3]*/, cgm_int nx, cgm_int ny, cgm_int local_color_precision, cgm_cell_representation_mode mode, const byte *values, uint source_bit, uint raster)
  433. {    int precision = local_color_precision;
  434.     int bits_per_pixel;
  435.     uint row_bytes;
  436.     const byte *row = values + (source_bit >> 3);
  437.     int bit = source_bit & 7;
  438.     int y;
  439.  
  440.     /* Currently we ignore the cell representation_mode, and always */
  441.     /* produce cell arrays in 'packed' format. */
  442.     mode = cgm_cell_mode_packed;
  443.     OP(CELL_ARRAY);
  444.     nP(pqr, 3); I(nx); I(ny); I(local_color_precision); E(mode);
  445.     if ( precision == 0 )
  446.       precision = (st->picture.color_selection_mode ==
  447.                  cgm_color_selection_indexed ?
  448.                st->metafile.color_index_precision :
  449.                st->metafile.color_precision);
  450.     bits_per_pixel =
  451.       (st->picture.color_selection_mode == cgm_color_selection_indexed ?
  452.        precision : precision * 3);
  453.     row_bytes = (bits_per_pixel * nx + 7) >> 3;
  454.     for ( y = 0; y < ny; y++, row += raster )
  455.       {    if ( bit == 0 )
  456.           put_bytes(st, row, row_bytes);
  457.         else
  458.           {    uint i;
  459.             for ( i = 0; i < row_bytes; i++ )
  460.               {    byte b = (row[i] << bit) +
  461.                   (row[i+1] >> (8 - bit));
  462.                 put_byte(st, b);
  463.               }
  464.           }
  465.         if ( (row_bytes & 1) )
  466.           {    put_byte(st, 0);
  467.           }
  468.       }
  469.     END;
  470. }
  471.  
  472. cgm_result
  473. cgm_RECTANGLE(cgm_state *st, const cgm_point *corner1, const cgm_point *corner2)
  474. {    OP(RECTANGLE);
  475.     P(corner1); P(corner2);
  476.     END;
  477. }
  478.  
  479. cgm_result
  480. cgm_CIRCLE(cgm_state *st, const cgm_point *center, const cgm_vdc *radius)
  481. {    OP(CIRCLE);
  482.     P(center); VDC(radius);
  483.     END;
  484. }
  485.  
  486. cgm_result
  487. cgm_CIRCULAR_ARC_3_POINT(cgm_state *st, const cgm_point *start, const cgm_point *intermediate, const cgm_point *end)
  488. {    OP(CIRCULAR_ARC_3_POINT);
  489.     P(start); P(intermediate); P(end);
  490.     END;
  491. }
  492.  
  493. cgm_result
  494. cgm_CIRCULAR_ARC_3_POINT_CLOSE(cgm_state *st, const cgm_point *start, const cgm_point *intermediate, const cgm_point *end, cgm_arc_closure closure)
  495. {    OP(CIRCULAR_ARC_3_POINT_CLOSE);
  496.     P(start); P(intermediate); P(end); E(closure);
  497.     END;
  498. }
  499.  
  500. cgm_result
  501. cgm_CIRCULAR_ARC_CENTER(cgm_state *st, const cgm_point *center, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, const cgm_vdc *radius)
  502. {    OP(CIRCULAR_ARC_CENTER);
  503.     P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius);
  504.     END;
  505. }
  506.  
  507. cgm_result
  508. cgm_CIRCULAR_ARC_CENTER_CLOSE(cgm_state *st, const cgm_point *center, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, const cgm_vdc *radius, cgm_arc_closure closure)
  509. {    OP(CIRCULAR_ARC_CENTER_CLOSE);
  510.     P(center); VDC4(dx_start, dy_start, dx_end, dy_end); VDC(radius);
  511.     E(closure);
  512.     END;
  513. }
  514.  
  515. cgm_result
  516. cgm_ELLIPSE(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end)
  517. {    OP(ELLIPSE);
  518.     P(center); P(cd1_end); P(cd2_end);
  519.     END;
  520. }
  521.  
  522. cgm_result
  523. cgm_ELLIPTICAL_ARC(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end)
  524. {    OP(ELLIPTICAL_ARC);
  525.     P(center); P(cd1_end); P(cd2_end);
  526.     VDC4(dx_start, dy_start, dx_end, dy_end);
  527.     END;
  528. }
  529.  
  530. cgm_result
  531. cgm_ELLIPTICAL_ARC_CLOSE(cgm_state *st, const cgm_point *center, const cgm_point *cd1_end, const cgm_point *cd2_end, const cgm_vdc *dx_start, const cgm_vdc *dy_start, const cgm_vdc *dx_end, const cgm_vdc *dy_end, cgm_arc_closure closure)
  532. {    OP(ELLIPTICAL_ARC_CLOSE);
  533.     P(center); P(cd1_end); P(cd2_end);
  534.     VDC4(dx_start, dy_start, dx_end, dy_end); E(closure);
  535.     END;
  536. }
  537.  
  538. /* ---------------- Attribute elements ---------------- */
  539.  
  540. cgm_result
  541. cgm_LINE_BUNDLE_INDEX(cgm_state *st, cgm_int index)
  542. {    OP(LINE_BUNDLE_INDEX);
  543.     IX(index);  st->line_bundle_index = index;
  544.     END;
  545. }
  546.  
  547. cgm_result
  548. cgm_LINE_TYPE(cgm_state *st, cgm_line_type line_type)
  549. {    OP(LINE_TYPE);
  550.     IX((int)line_type);  st->line_type = line_type;
  551.     END;
  552. }
  553.  
  554. cgm_result
  555. cgm_LINE_WIDTH(cgm_state *st, const cgm_line_width *line_width)
  556. {    OP(LINE_WIDTH);
  557.     VDC_R(line_width, st->picture.line_width_specification_mode);
  558.     st->line_width = *line_width;
  559.     END;
  560. }
  561.  
  562. cgm_result
  563. cgm_LINE_COLOR(cgm_state *st, const cgm_color *color)
  564. {    OP(LINE_COLOR);
  565.     CO(color);  st->line_color = *color;
  566.     END;
  567. }
  568.  
  569. cgm_result
  570. cgm_MARKER_BUNDLE_INDEX(cgm_state *st, cgm_int index)
  571. {    OP(MARKER_BUNDLE_INDEX);
  572.     IX(index);  st->marker_bundle_index = index;
  573.     END;
  574. }
  575.  
  576. cgm_result
  577. cgm_MARKER_TYPE(cgm_state *st, cgm_marker_type marker_type)
  578. {    OP(MARKER_TYPE);
  579.     IX((int)marker_type);  st->marker_type = marker_type;
  580.     END;
  581. }
  582.  
  583. cgm_result
  584. cgm_MARKER_SIZE(cgm_state *st, const cgm_marker_size *marker_size)
  585. {    OP(MARKER_SIZE);
  586.     VDC_R(marker_size, st->picture.marker_size_specification_mode);
  587.     st->marker_size = *marker_size;
  588.     END;
  589. }
  590.  
  591. cgm_result
  592. cgm_MARKER_COLOR(cgm_state *st, const cgm_color *color)
  593. {    OP(MARKER_COLOR);
  594.     CO(color);  st->marker_color = *color;
  595.     END;
  596. }
  597.  
  598. cgm_result
  599. cgm_TEXT_BUNDLE_INDEX(cgm_state *st, cgm_int index)
  600. {    OP(TEXT_BUNDLE_INDEX);
  601.     IX(index);  st->text_bundle_index = index;
  602.     END;
  603. }
  604.  
  605. cgm_result
  606. cgm_TEXT_FONT_INDEX(cgm_state *st, cgm_int index)
  607. {    OP(TEXT_FONT_INDEX);
  608.     IX(index);  st->text_font_index = index;
  609.     END;
  610. }
  611.  
  612. cgm_result
  613. cgm_TEXT_PRECISION(cgm_state *st, cgm_text_precision precision)
  614. {    OP(TEXT_PRECISION);
  615.     E(precision);  st->text_precision = precision;
  616.     END;
  617. }
  618.  
  619. cgm_result
  620. cgm_CHARACTER_EXPANSION_FACTOR(cgm_state *st, cgm_real factor)
  621. {    OP(CHARACTER_EXPANSION_FACTOR);
  622.     R(factor);  st->character_expansion_factor = factor;
  623.     END;
  624. }
  625.  
  626. cgm_result
  627. cgm_CHARACTER_SPACING(cgm_state *st, cgm_real spacing)
  628. {    OP(CHARACTER_SPACING);
  629.     R(spacing);  st->character_spacing = spacing;
  630.     END;
  631. }
  632.  
  633. cgm_result
  634. cgm_TEXT_COLOR(cgm_state *st, const cgm_color *color)
  635. {    OP(TEXT_COLOR);
  636.     CO(color);  st->text_color = *color;
  637.     END;
  638. }
  639.  
  640. cgm_result
  641. cgm_CHARACTER_HEIGHT(cgm_state *st, const cgm_vdc *height)
  642. {    OP(CHARACTER_HEIGHT);
  643.     VDC(height);  st->character_height = *height;
  644.     END;
  645. }
  646.  
  647. cgm_result
  648. cgm_CHARACTER_ORIENTATION(cgm_state *st, const cgm_vdc *x_up, const cgm_vdc *y_up, const cgm_vdc *x_base, const cgm_vdc *y_base)
  649. {    OP(CHARACTER_ORIENTATION);
  650.     VDC4(x_up, y_up, x_base, y_base);
  651.     st->character_orientation[0] = *x_up;
  652.     st->character_orientation[1] = *y_up;
  653.     st->character_orientation[2] = *x_base;
  654.     st->character_orientation[3] = *y_base;
  655.     END;
  656. }
  657.  
  658. cgm_result
  659. cgm_TEXT_PATH(cgm_state *st, cgm_text_path text_path)
  660. {    OP(TEXT_PATH);
  661.     E(text_path);  st->text_path = text_path;
  662.     END;
  663. }
  664.  
  665. cgm_result
  666. cgm_TEXT_ALIGNMENT(cgm_state *st, cgm_text_alignment_horizontal align_h, cgm_text_alignment_vertical align_v, cgm_real align_cont_h, cgm_real align_cont_v)
  667. {    OP(TEXT_ALIGNMENT);
  668.     E(align_h); E(align_v); R(align_cont_h); R(align_cont_v);
  669.     END;
  670. }
  671.  
  672. cgm_result
  673. cgm_CHARACTER_SET_INDEX(cgm_state *st, cgm_int index)
  674. {    OP(CHARACTER_SET_INDEX);
  675.     IX(index);  st->character_set_index = index;
  676.     END;
  677. }
  678.  
  679. /* See gdevcgml.c for why this isn't named cgm_ALTERNATE_.... */
  680. cgm_result
  681. cgm_ALT_CHARACTER_SET_INDEX(cgm_state *st, cgm_int index)
  682. {    OP(ALTERNATE_CHARACTER_SET_INDEX);
  683.     IX(index);  st->alternate_character_set_index = index;
  684.     END;
  685. }
  686.  
  687. cgm_result
  688. cgm_FILL_BUNDLE_INDEX(cgm_state *st, cgm_int index)
  689. {    OP(FILL_BUNDLE_INDEX);
  690.     IX(index);  st->fill_bundle_index = index;
  691.     END;
  692. }
  693.  
  694. cgm_result
  695. cgm_INTERIOR_STYLE(cgm_state *st, cgm_interior_style interior_style)
  696. {    OP(INTERIOR_STYLE);
  697.     E(interior_style);  st->interior_style = interior_style;
  698.     END;
  699. }
  700.  
  701. cgm_result
  702. cgm_FILL_COLOR(cgm_state *st, const cgm_color *color)
  703. {    OP(FILL_COLOR);
  704.     CO(color);  st->fill_color = *color;
  705.     END;
  706. }
  707.  
  708. cgm_result
  709. cgm_HATCH_INDEX(cgm_state *st, cgm_hatch_index hatch_index)
  710. {    OP(HATCH_INDEX);
  711.     IX((int)hatch_index);  st->hatch_index = hatch_index;
  712.     END;
  713. }
  714.  
  715. cgm_result
  716. cgm_PATTERN_INDEX(cgm_state *st, cgm_int index)
  717. {    OP(PATTERN_INDEX);
  718.     IX(index);  st->pattern_index = index;
  719.     END;
  720. }
  721.  
  722. cgm_result
  723. cgm_EDGE_BUNDLE_INDEX(cgm_state *st, cgm_int index)
  724. {    OP(EDGE_BUNDLE_INDEX);
  725.     IX(index);  st->edge_bundle_index = index;
  726.     END;
  727. }
  728.  
  729. cgm_result
  730. cgm_EDGE_TYPE(cgm_state *st, cgm_edge_type edge_type)
  731. {    OP(EDGE_TYPE);
  732.     IX((int)edge_type);  st->edge_type = edge_type;
  733.     END;
  734. }
  735.  
  736. cgm_result
  737. cgm_EDGE_WIDTH(cgm_state *st, const cgm_edge_width *edge_width)
  738. {    OP(EDGE_WIDTH);
  739.     VDC_R(edge_width, st->picture.edge_width_specification_mode);
  740.     st->edge_width = *edge_width;
  741.     END;
  742. }
  743.  
  744. cgm_result
  745. cgm_EDGE_COLOR(cgm_state *st, const cgm_color *color)
  746. {    OP(EDGE_COLOR);
  747.     CO(color);
  748.     END;
  749. }
  750.  
  751. cgm_result
  752. cgm_EDGE_VISIBILITY(cgm_state *st, bool visibility)
  753. {    OP(EDGE_VISIBILITY);
  754.     E(visibility);  st->edge_visibility = visibility;
  755.     END;
  756. }
  757.  
  758. cgm_result
  759. cgm_FILL_REFERENCE_POINT(cgm_state *st, const cgm_point *reference_point)
  760. {    OP(FILL_REFERENCE_POINT);
  761.     P(reference_point);  st->fill_reference_point = *reference_point;
  762.     END;
  763. }
  764.  
  765. /* PATTERN_TABLE */
  766.  
  767. cgm_result
  768. cgm_PATTERN_SIZE(cgm_state *st, const cgm_vdc *x_height, const cgm_vdc *y_height, const cgm_vdc *x_width, const cgm_vdc *y_width)
  769. {    OP(PATTERN_SIZE);
  770.     VDC4(x_height, y_height, x_width, y_width);
  771.     st->pattern_size[0] = *x_height;
  772.     st->pattern_size[1] = *y_height;
  773.     st->pattern_size[2] = *x_width;
  774.     st->pattern_size[3] = *y_width;
  775.     END;
  776. }
  777.  
  778. cgm_result
  779. cgm_COLOR_TABLE(cgm_state *st, cgm_int index, const cgm_color *values, int count)
  780. {    int i;
  781.     OP(COLOR_TABLE);
  782.     CI(index);
  783.     for ( i = 0; i < count; ++i )
  784.       CD(&values[i].rgb);
  785.     END;
  786. }
  787.  
  788. cgm_result cgm_ASPECT_SOURCE_FLAGS(cgm_state *st, const cgm_aspect_source_flag *flags, int count)
  789. {    int i;
  790.     OP(ASPECT_SOURCE_FLAGS);
  791.     for ( i = 0; i < count; ++i )
  792.     {    E(flags[i].type); E(flags[i].source);
  793.         st->source_flags[flags[i].type] = (byte)flags[i].source;
  794.     }
  795.     END;
  796. }
  797.  
  798. /* ================ Internal routines ================ */
  799.  
  800. /* Begin a command. */
  801. private void
  802. begin_command(cgm_state *st, cgm_op_index op)
  803. {    uint op_word = (uint)op << cgm_op_id_shift;
  804.     st->command[0] = (byte)(op_word >> 8);
  805.     st->command[1] = (byte)(op_word);
  806.     st->command_count = 4;        /* leave room for extension */
  807.     st->command_first = true;
  808.     st->result = cgm_result_ok;
  809. }
  810.  
  811. /* Write the buffer for a partial command. */
  812. /* Note that we always write an even number of bytes. */
  813. private void
  814. write_command(cgm_state *st, bool last)
  815. {    byte *command = st->command;
  816.     int count = st->command_count;
  817.     if ( st->command_first )
  818.     {    if ( count <= 34 )
  819.         {    command[2] = command[0];
  820.             command[3] = command[1] + count - 4;
  821.             command += 2, count -= 2;
  822.         }
  823.         else
  824.         {    int pcount = count - 4;
  825.             command[1] |= 31;
  826.             command[2] = (byte)(pcount >> 8);
  827.             if ( !last ) command[2] |= 0x80;
  828.             command[3] = (byte)pcount;
  829.         }
  830.         st->command_first = false;
  831.     }
  832.     else
  833.     {    int pcount = count - 2;
  834.         command[0] = (byte)(pcount >> 8);
  835.         if ( !last ) command[0] |= 0x80;
  836.         command[1] = (byte)pcount;
  837.     }
  838.     fwrite(command, sizeof(byte), count + (count & 1), st->file);
  839.     st->command_count = 2;        /* leave room for extension header */
  840.     if ( ferror(st->file) )
  841.       st->result = cgm_result_io_error;
  842. }
  843.  
  844. /* End a command. */
  845. private cgm_result
  846. end_command(cgm_state *st)
  847. {    write_command(st, true);
  848.     return st->result;
  849. }
  850.  
  851. /* Put an integer value. */
  852. private void
  853. put_int(cgm_state *st, cgm_int value, int precision)
  854. {    switch ( precision )
  855.     {
  856.     case 32:
  857.         put_byte(st, value >> 24);
  858.     case 24:
  859.         put_byte(st, value >> 16);
  860.     case 16:
  861.         put_byte(st, value >> 8);
  862.     case 8:
  863.         put_byte(st, value);
  864.     }
  865. }
  866.  
  867. /* Put a real value. */
  868. private void
  869. put_real(cgm_state *st, cgm_real value, const cgm_precision *pr)
  870. {    if ( pr->representation == cgm_representation_floating )
  871.     {
  872.     }
  873.     else
  874.     {    /* Casting to integer simply discards the fraction, */
  875.         /* so we need to be careful with negative values. */
  876.         long whole = (long)value;
  877.         double fpart;
  878.         if ( value < whole ) --whole;
  879.         fpart = value - whole;
  880.         put_int(st, whole, pr->exponent_or_whole_width);
  881.         if ( pr->fraction_width == 16 )
  882.         {    uint fraction = (uint)(fpart * (1.0 * 0x10000));
  883.             put_int(st, fraction, 16);
  884.         }
  885.         else    /* pr->fraction_width == 32 */
  886.         {    ulong fraction =
  887.               (ulong)(fpart * (1.0 * 0x10000 * 0x10000));
  888.             put_int(st, fraction, 32);
  889.         }
  890.     }
  891. }
  892.  
  893. /* Put a real precision. */
  894. private void
  895. put_real_precision(cgm_state *st, const cgm_precision *precision)
  896. {    I((int)precision->representation);
  897.     I(precision->exponent_or_whole_width);
  898.     I(precision->fraction_width);
  899. }
  900.  
  901. /* Put a VDC. */
  902. private void
  903. put_vdc(cgm_state *st, const cgm_vdc *pvdc)
  904. {    if ( st->metafile.vdc_type == cgm_vdc_integer )
  905.       put_int(st, pvdc->integer, st->vdc_integer_precision);
  906.     else
  907.       put_real(st, pvdc->real, &st->vdc_real_precision);
  908. }
  909.  
  910. /* Put a VDC or a real. */
  911. private void
  912. put_vdc_r(cgm_state *st, const cgm_line_marker_extent *extent,
  913.   cgm_line_marker_specification_mode mode)
  914. {    if ( mode == cgm_line_marker_absolute )
  915.       VDC(&extent->absolute);
  916.     else
  917.       R(extent->scaled);
  918. }
  919.  
  920. /* Put a point (pair of VDCs). */
  921. private void
  922. put_point(cgm_state *st, const cgm_point *ppt)
  923. {    if ( st->metafile.vdc_type == cgm_vdc_integer )
  924.     {    put_int(st, ppt->integer.x, st->vdc_integer_precision);
  925.         put_int(st, ppt->integer.y, st->vdc_integer_precision);
  926.     }
  927.     else
  928.     {    put_real(st, ppt->real.x, &st->vdc_real_precision);
  929.         put_real(st, ppt->real.y, &st->vdc_real_precision);
  930.     }
  931. }
  932.  
  933. /* Put a list of points. */
  934. private void
  935. put_points(cgm_state *st, const cgm_point *ppt, int count)
  936. {    int i;
  937.     for ( i = 0; i < count; i++ )
  938.       P(ppt + i);
  939. }
  940.  
  941. /* Put bytes. */
  942. private void
  943. put_bytes(cgm_state *st, const byte *data, uint length)
  944. {    int count;
  945.     while ( length > (count = command_max_count - st->command_count) )
  946.     {    memcpy(st->command + st->command_count, data, count);
  947.         st->command_count += count;
  948.         write_command(st, false);
  949.         data += count;
  950.         length -= count;
  951.     }
  952.     memcpy(st->command + st->command_count, data, length);
  953.     st->command_count += length;
  954. }
  955.  
  956. /* Put a string. */
  957. private void
  958. put_string(cgm_state *st, const char *data, uint length)
  959. {    /* The CGM specification seems to imply that the continuation */
  960.     /* mechanism for commands and the mechanism for strings */
  961.     /* are orthogonal; we take this interpretation. */
  962.     if ( length >= 255 )
  963.     {    put_byte(st, 255);
  964.         while ( length > 32767 )
  965.         {    put_int(st, 65535, 2);
  966.             put_bytes(st, (const byte *)data, 32767);
  967.             data += 32767;
  968.             length -= 32767;
  969.         }
  970.     }
  971.     put_byte(st, length);
  972.     put_bytes(st, (const byte *)data, length);
  973. }
  974.  
  975. /* Put a color. */
  976. private void
  977. put_color(cgm_state *st, const cgm_color *color)
  978. {    if ( st->picture.color_selection_mode == cgm_color_selection_indexed )
  979.       CI(color->index);
  980.     else
  981.       CD(&color->rgb);
  982. }
  983.  
  984. /* Put an RGB value. */
  985. private void
  986. put_rgb(cgm_state *st, const cgm_rgb *rgb)
  987. {    put_int(st, rgb->r, st->metafile.color_precision);
  988.     put_int(st, rgb->g, st->metafile.color_precision);
  989.     put_int(st, rgb->b, st->metafile.color_precision);
  990. }
  991.